/**
 * @file throttle.js
 */


var $ = Zepto;

/**
 * 减少执行频率, 多次调用，在指定的时间内，只会执行一次。
 * ```
 * ||||||||||||||||||||||||| (空闲) |||||||||||||||||||||||||
 * X    X    X    X    X    X      X    X    X    X    X    X
 * ```
 * @method $.throttle
 * @grammar $.throttle(delay, fn) ⇒ function
 * @param {Number} [delay=250] 延时时间
 * @param {Function} fn 被稀释的方法
 * @param {Boolean} [debounce_mode=false] 是否开启防震动模式, true:start, false:end
 * @example var touchmoveHander = function(){
 *     //....
 * }
 * //绑定事件
 * $(document).bind('touchmove', $.throttle(250, touchmoveHander));//频繁滚动，每250ms，执行一次touchmoveHandler
 *
 * //解绑事件
 * $(document).unbind('touchmove', touchmoveHander);//注意这里面unbind还是touchmoveHander,而不是$.throttle返回的function, 当然unbind那个也是一样的效果
 *
 */
$.extend($, {
    throttle: function (delay, fn, debounce_mode) {
        var last = 0;
        var timeId;

        if (typeof fn !== 'function') {
            debounce_mode = fn;
            fn = delay;
            delay = 250;
        }

        function wrapper() {
            var that = this;
            var period = Date.now() - last;
            var args = arguments;

            function exec() {
                last = Date.now();
                fn.apply(that, args);
            }

            function clear() {
                timeId = undefined;
            }

            if (debounce_mode && !timeId) {
                // debounce模式 && 第一次调用
                exec();
            }

            timeId && clearTimeout(timeId);
            if (debounce_mode === undefined && period > delay) {
                // throttle, 执行到了delay时间
                exec();
            }
            else {
                // debounce, 如果是start就clearTimeout
                timeId = setTimeout(debounce_mode ? clear : exec, debounce_mode === undefined ? delay - period : delay);
            }
        }
        // for event bind | unbind
        wrapper._zid = fn._zid = fn._zid || $.proxy(fn)._zid;
        return wrapper;
    },

    /**
     * @desc 减少执行频率, 在指定的时间内, 多次调用，只会执行一次。
     * **options:**
     * - ***delay***: 延时时间
     * - ***fn***: 被稀释的方法
     * - ***t***: 指定是在开始处执行，还是结束是执行, true:start, false:end
     *
     * 非at_begin模式
     * <code type="text">||||||||||||||||||||||||| (空闲) |||||||||||||||||||||||||
     *                         X                                X</code>
     * at_begin模式
     * <code type="text">||||||||||||||||||||||||| (空闲) |||||||||||||||||||||||||
     * X                                X                        </code>
     *
     * @grammar $.debounce(delay, fn[, at_begin]) ⇒ function
     * @name $.debounce
     * @example var touchmoveHander = function(){
     *     //....
     * }
     * //绑定事件
     * $(document).bind('touchmove', $.debounce(250, touchmoveHander));//频繁滚动，只要间隔时间不大于250ms, 在一系列移动后，只会执行一次
     *
     * //解绑事件
     * $(document).unbind('touchmove', touchmoveHander);//注意这里面unbind还是touchmoveHander,而不是$.debounce返回的function, 当然unbind那个也是一样的效果
     */
    debounce: function (delay, fn, t) {
        return fn === undefined ? $.throttle(250, delay, false) : $.throttle(delay, fn, t === undefined ? false : t !== false);
    }

});
